﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using SDMX_ML.Framework.Interfaces;
using SDMX_Message = SDMX_ML.Framework.Message;
using SDMX_Common = SDMX_ML.Framework.Common;
using SDMX_Metadata = SDMX_ML.Framework.Metadata;

namespace SDMX_ML.Framework.Messages
{
    public class GenericMetadata : IMessage
    {
        private XElement _xml;
        private XDocument _xmldoc;
        private XNamespace _nsStructurMessage;
        private XNamespace _nsGenericMetadata;
        private XNamespace _nsMessage;
        private XNamespace _nsCommon;
        private SDMX_Message.HeaderType _header;
        private SDMX_Metadata.MetadataSetType _metadataSet;

        

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="genericMetadata">Xml as string.</param>
        public GenericMetadata(string genericMetadata)
        {
            //GenerateLists();

            _xml = XElement.Parse(genericMetadata);

            setNameSpace();

            SetGenericData();

        }

        private void setNameSpace()
        {
            _nsStructurMessage = _xml.Name.Namespace;


            //Finding the prefix used for the structure namespace
            string prefixgenericMetadata = _xml.GetPrefixOfNamespace(Namespaces.GetNS("genericmetadata"));

            if (prefixgenericMetadata != null)
            {
                //create the structure namespace used in the xml structure file
                _nsGenericMetadata = _xml.GetNamespaceOfPrefix(prefixgenericMetadata);
            }
            else
            {
                _nsGenericMetadata = _xml.GetDefaultNamespace();
            }

            //Finding the prefix used for the common namespace
            string prefixCommon = _xml.GetPrefixOfNamespace(Namespaces.GetNS("common"));
            //create the common namespace used in the xml structure file

            if (prefixCommon != null)
            {
                _nsCommon = _xml.GetNamespaceOfPrefix(prefixCommon);
            }

            //Finding the prefix used for the message namespace
            string prefixMessage = _xml.GetPrefixOfNamespace(Namespaces.GetNS("message"));

            if (prefixMessage != null)
            {
                //create the common namespace used in the xml structure file
                _nsMessage = _xml.GetNamespaceOfPrefix(prefixMessage);
            }
            else
            {
                _nsMessage = _xml.GetDefaultNamespace();
            }


        }

        private void SetGenericData()
        {
            XElement header = _xml.Element(_nsMessage + "Header");
            XElement metadataSet = _xml.Element(_nsGenericMetadata + "MetadataSet");


            if (header != null)
            {
                _header = new SDMX_Message.HeaderType(header);
            }

            if(metadataSet != null)
            {
                SetMetadataSet(metadataSet);
            }
            
        }

        private void SetMetadataSet(XElement metadataSet)
        {
            //SDMX_Metadata.MetadataSetType metadataType = null;

            if (metadataSet.Element(_nsGenericMetadata + "MetadataStructureRef") != null &
                metadataSet.Element(_nsGenericMetadata + "MetadataStructureAgencyRef") != null &
                metadataSet.Element(_nsGenericMetadata + "ReportRef") != null &
                metadataSet.Element(_nsGenericMetadata + "AttributeValueSet") != null)
            {
                SDMX_Common.IDType metadataStructureRef = null;
                SDMX_Common.IDType metadataStructureAgencyRef = null;
                SDMX_Common.IDType reportRef = null;
                SDMX_Metadata.AttributesValueSetType attributeValueSet = null;

                if (metadataSet.Element(_nsGenericMetadata + "MetadataStructureRef").Value != null)
                {
                    metadataStructureRef = new SDMX_Common.IDType(metadataSet.Element(_nsGenericMetadata + "MetadataStructureRef").Value);
                }
                else
                {
                    throw new Exception("Value in MetadataStructureRef element is required!");
                }

                if (metadataSet.Element(_nsGenericMetadata + "MetadataStructureAgencyRef").Value != null)
                {
                    metadataStructureAgencyRef = new SDMX_Common.IDType(metadataSet.Element(_nsGenericMetadata + "MetadataStructureAgencyRef").Value);
                }
                else
                {
                    throw new Exception("Value in MetadataStructureAgencyRef element is required!");
                }

                if (metadataSet.Element(_nsGenericMetadata + "ReportRef").Value != null)
                {
                    reportRef = new SDMX_Common.IDType(metadataSet.Element(_nsGenericMetadata + "ReportRef").Value);
                }
                else
                {
                    throw new Exception("Value in ReportRef element is required!");
                }

                if (metadataSet.Element(_nsGenericMetadata + "AttributeValueSet") != null)
                {
                    foreach (XElement e in metadataSet.Elements(_nsGenericMetadata + "AttributeValueSet"))
                    {
                        attributeValueSet = GetAttributeValueSetType(e);

                        if (_metadataSet == null)
                        {
                            _metadataSet = new SDMX_Metadata.MetadataSetType(metadataStructureRef, metadataStructureAgencyRef, reportRef, attributeValueSet);
                        }
                        else
                        {
                            _metadataSet.AttributeValueSet.Add(attributeValueSet);
                        }
                    }
                }
                else
                {
                    throw new Exception("AttributeValueSet element is required!");
                }
            }
            else
            {
                throw new Exception("The elments MetadataStructureRef, MetadataStructureAgencyRef, ReportRef, AttributeValueSet are required fields in MetadataSet");
            }

            if (metadataSet.Element(_nsGenericMetadata + "Name") != null)
            {
                foreach (XElement name in metadataSet.Elements(_nsGenericMetadata + "Name"))
                {
                    _metadataSet.Name.Add(ObjectBuilder.GetTextType(name));
                }
            }

            if (metadataSet.Element(_nsGenericMetadata + "Annotations") != null)
            {
                _metadataSet.Annotations = ObjectBuilder.GetAnnotationsType(metadataSet.Element(_nsGenericMetadata + "Annotations"));
            }

            if (metadataSet.Attribute("metadataStructureURI") != null)
            {
                if (metadataSet.Attribute("metadataStructureURI").Value != null)
                {
                    _metadataSet.MetadataStructureURI = metadataSet.Attribute("metadataStructureURI").Value;
                }
            }

            if (metadataSet.Attribute("datasetID") != null)
            {
                if (metadataSet.Attribute("datasetID").Value != null)
                {
                    _metadataSet.DatasetID = ObjectBuilder.GetIDType(metadataSet.Attribute("datasetID").Value);
                }
            }

            if (metadataSet.Attribute("dataProviderSchemeAgencyId") != null)
            {
                if (metadataSet.Attribute("dataProviderSchemeAgencyId").Value != null)
                {
                    _metadataSet.DataProviderSchemeAgencyId = ObjectBuilder.GetIDType(metadataSet.Attribute("dataProviderSchemeAgencyId").Value);
                }
            }

            if (metadataSet.Attribute("dataProviderSchemeId") != null)
            {
                if (metadataSet.Attribute("dataProviderSchemeId").Value != null)
                {
                    _metadataSet.DataProviderSchemeId = ObjectBuilder.GetIDType(metadataSet.Attribute("dataProviderSchemeId").Value);
                }
            }

            if (metadataSet.Attribute("dataProviderID") != null)
            {
                if (metadataSet.Attribute("dataProviderID").Value != null)
                {
                    _metadataSet.DataProviderID = ObjectBuilder.GetIDType(metadataSet.Attribute("dataProviderID").Value);
                }
            }

            if (metadataSet.Attribute("dataflowAgencyID") != null)
            {
                if (metadataSet.Attribute("dataflowAgencyID").Value != null)
                {
                    _metadataSet.DataflowAgencyID = ObjectBuilder.GetIDType(metadataSet.Attribute("dataflowAgencyID").Value);
                }
            }

            if (metadataSet.Attribute("dataflowID") != null)
            {
                if (metadataSet.Attribute("dataflowID").Value != null)
                {
                    _metadataSet.DataflowID = ObjectBuilder.GetIDType(metadataSet.Attribute("dataflowID").Value);
                }
            }

            if (metadataSet.Attribute("action") != null)
            {
                if (metadataSet.Attribute("action").Value != null)
                {
                    _metadataSet.Action = SDMX_Common.EnumerationConvert.EnumDataSetActionFromString(metadataSet.Attribute("action").Value);
                }
            }

            if (metadataSet.Attribute("reportingBeginDate") != null)
            {
                if (metadataSet.Attribute("reportingBeginDate").Value != null)
                {
                    _metadataSet.ReportingBeginDate = metadataSet.Attribute("reportingBeginDate").Value;
                }
            }

            if (metadataSet.Attribute("reportingEndDate") != null)
            {
                if (metadataSet.Attribute("reportingEndDate").Value != null)
                {
                    _metadataSet.ReportingEndDate = metadataSet.Attribute("reportingEndDate").Value;
                }
            }

            if (metadataSet.Attribute("validFromDate") != null)
            {
                if (metadataSet.Attribute("validFromDate").Value != null)
                {
                    _metadataSet.ValidFromDate = metadataSet.Attribute("validFromDate").Value;
                }
            }

            if (metadataSet.Attribute("validToDate") != null)
            {
                if (metadataSet.Attribute("validToDate").Value != null)
                {
                    _metadataSet.ValidToDate = metadataSet.Attribute("validToDate").Value;
                }
            }

            if (metadataSet.Attribute("publicationYear") != null)
            {
                if (metadataSet.Attribute("publicationYear").Value != null)
                {
                    _metadataSet.PublicationYear = metadataSet.Attribute("publicationYear").Value;
                }
            }

            if (metadataSet.Attribute("publicationPeriod") != null)
            {
                if (metadataSet.Attribute("publicationPeriod").Value != null)
                {
                    _metadataSet.PublicationPeriod = metadataSet.Attribute("publicationPeriod").Value;
                }
            }
        }

        private SDMX_Metadata.AttributesValueSetType GetAttributeValueSetType(XElement element)
        {
            SDMX_Common.IDType targetRef = null;
            SDMX_Metadata.TargetValuesType targetValuesType = null;
            SDMX_Metadata.AttributesValueSetType attributesValueType = null;;

            if (element.Element(_nsGenericMetadata + "TargetRef") != null)
            {
                targetRef = ObjectBuilder.GetIDType(element.Element(_nsGenericMetadata + "TargetRef").Value);
            }
            else
            {
                throw new Exception("Element TargetRef in AttributeValueSet is a required element.");
            }

            if (element.Element(_nsGenericMetadata + "TargetValues") != null)
            {
                XElement targetValues = element.Element(_nsGenericMetadata + "TargetValues");
                IEnumerable<XElement> compValues = targetValues.Elements(_nsGenericMetadata + "ComponentValue");

                foreach (XElement e in compValues)
                {
                    SDMX_Metadata.ComponentValueType componentValueType = GetComponentValueType(e);

                    if (targetValuesType == null)
                    {
                        targetValuesType = new SDMX_Metadata.TargetValuesType(componentValueType);
                    }
                    else
                    {
                        targetValuesType.ComponentValue.Add(GetComponentValueType(e));
                    }
                }
            }
            else
            {
                throw new Exception("Element TargetValues in AttributeValueSet is a required element.");
            }

            if (element.Element(_nsGenericMetadata + "ReportedAttribute") != null)
            {
                
                foreach (XElement e in element.Elements(_nsGenericMetadata + "ReportedAttribute"))
                {
                    SDMX_Metadata.ReportedAttributeType reportedAttribueType = GetReportedAttributeType(e);

                    if (attributesValueType == null)
                    {
                        attributesValueType = new SDMX_Metadata.AttributesValueSetType(targetRef, targetValuesType, reportedAttribueType);
                    }
                    else
                    {
                        attributesValueType.ReportedAttribute.Add(reportedAttribueType);
                    }
                }
            }
            else
            {
                throw new Exception("Element ReportedAttribute in AttributeValueSet is a required element.");
            }

            return attributesValueType;
        }

        private SDMX_Metadata.ReportedAttributeType GetReportedAttributeType(XElement element)
        {
            SDMX_Metadata.ReportedAttributeType reportedAttributeType = null;

            if (element.Attribute("conceptID") != null)
            {
                if (element.Attribute("conceptID").Value != null)
                {
                    SDMX_Common.IDType idType = ObjectBuilder.GetIDType(element.Attribute("conceptID").Value);
                    reportedAttributeType = new SDMX_Metadata.ReportedAttributeType(idType);
                }
                else
                {
                    throw new Exception("Value in attribute conceptID is a required value in ReportedAttribute");
                }
            }
            else
            {
                throw new Exception("Attribute conceptID is a required attribute in ReportedAttribute");
            }

            if (element.Element(_nsGenericMetadata + "Value") != null)
            {
                foreach (XElement e in element.Elements(_nsGenericMetadata + "Value"))
                {
                    if (e.Value != null)
                    {
                        reportedAttributeType.Value.Add(ObjectBuilder.GetTextType(e));
                    }
                }
            }

            if (element.Element(_nsGenericMetadata + "StartTime") != null)
            {
                if (element.Element(_nsGenericMetadata + "StartTime").Value != null)
                {
                    reportedAttributeType.StartTime = element.Element(_nsGenericMetadata + "StartTime").Value;
                }
            }

            if (element.Element(_nsGenericMetadata + "ReportedAttribute") != null)
            {
                foreach (XElement e in element.Elements(_nsGenericMetadata + "ReportedAttribute"))
                {
                    reportedAttributeType.ReportedAttribute.Add(GetReportedAttributeType(e));
                }
                
            }

            if (element.Element(_nsGenericMetadata + "Annotations") != null)
            {
                reportedAttributeType.Annotations = ObjectBuilder.GetAnnotationsType(element.Element(_nsGenericMetadata + "Annotations"));
            }

            return reportedAttributeType;
        }

        private SDMX_Metadata.ComponentValueType GetComponentValueType(XElement element)
        {
            SDMX_Metadata.ComponentValueType componentValueType = null;

            

                if (element.Attribute("object") != null)
                {
                    if (element.Attribute("object").Value != null)
                    {
                        SDMX_Metadata.ObjectIDType objectIDType = SDMX_Metadata.EnumerationConvert.EnumObjectIDTypeFromString(element.Attribute("object").Value);
                        componentValueType = new SDMX_Metadata.ComponentValueType(objectIDType);

                        if (element.Value != null)
                        {
                            componentValueType.Component = ObjectBuilder.GetIDType(element.Value);
                        }
                    }
                    else
                    {
                        throw new Exception("Value in attribute object is a required value in ComponentValue.");
                    }
                }
                else
                {
                    throw new Exception("Attribute object is a required attribute in ComponentValue.");
                }
            

            

            if (element.Attribute("component") != null)
            {
                if (element.Attribute("component").Value != null)
                {
                    componentValueType.Component = ObjectBuilder.GetIDType(element.Attribute("component").Value);
                }
            }

            return componentValueType;

        }

        /// <summary>
        /// MetadataSet.
        /// </summary>
        public SDMX_Metadata.MetadataSetType MetadataSet
        {
            get { return _metadataSet; }
            set { _metadataSet = value; }
        }

        /// <summary>
        /// Headertype for message.
        /// </summary>
        public SDMX_Message.HeaderType Header
        {
            get { return _header; }
            set { _header = value; }
        }

        /// <summary>
        /// Get message as string.
        /// </summary>
        /// <returns>Xml as string.</returns>
        public string ToXml()
        {
            try
            {
                XElement x = GetXml();
                return x.ToString();
                //return _xmldoc.ToString();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Get message as XElement.
        /// </summary>
        /// <returns>Message as XElement.</returns>
        public System.Xml.Linq.XElement GetXml()
        {
            _xmldoc = new XDocument(
                new XDeclaration("1.0", "UTF-8", "yes"));

            XElement genericMetadata = new XElement(Namespaces.GetAllNamespaces("GenericMetadata"));

            if (_header != null)
            {
                genericMetadata.Add(_header.GetXml());
            }

            if (_metadataSet != null)
            {
                genericMetadata.Add(SetMetadataSet());
            }

            return genericMetadata;
        }

        private XElement SetMetadataSet()
        {
            XElement metadataSet = new XElement(_nsGenericMetadata + "MetadataSet");

            //Attributes
            if (!String.IsNullOrEmpty(_metadataSet.MetadataStructureURI))
            {
                metadataSet.Add(new XAttribute("metadataStructureURI", _metadataSet.MetadataStructureURI));
            }

            if (_metadataSet.DatasetID != null)
            {
                if (_metadataSet.DatasetID.Value != null)
                {
                    metadataSet.Add(new XAttribute("datasetID", _metadataSet.DatasetID.Value));
                }
            }

            if (_metadataSet.DataProviderSchemeAgencyId != null)
            {
                if (_metadataSet.DataProviderSchemeAgencyId.Value != null)
                {
                    metadataSet.Add(new XAttribute("dataProviderSchemeAgencyId", _metadataSet.DataProviderSchemeAgencyId.Value));
                }
            }

            if (_metadataSet.DataProviderSchemeId != null)
            {
                if (_metadataSet.DataProviderSchemeId.Value != null)
                {
                    metadataSet.Add(new XAttribute("dataProviderSchemeId", _metadataSet.DataProviderSchemeId.Value));
                }
            }

            if (_metadataSet.DataProviderID != null)
            {
                if (_metadataSet.DataProviderID.Value != null)
                {
                    metadataSet.Add(new XAttribute("dataProviderID", _metadataSet.DataProviderID.Value));
                }
            }

            if (_metadataSet.DataflowAgencyID != null)
            {
                if (_metadataSet.DataflowAgencyID.Value != null)
                {
                    metadataSet.Add(new XAttribute("dataflowAgencyID", _metadataSet.DataflowAgencyID.Value));
                }
            }

            if (_metadataSet.DataflowID != null)
            {
                if (_metadataSet.DataflowID.Value != null)
                {
                    metadataSet.Add(new XAttribute("dataflowID", _metadataSet.DataflowID.Value));
                }
            }

            if (_metadataSet.Action != null)
            {
                metadataSet.Add(new XAttribute("action", _metadataSet.Action.ToString()));
            }

            if (!String.IsNullOrEmpty(_metadataSet.ReportingBeginDate))
            {
                metadataSet.Add(new XAttribute("reportingBeginDate", _metadataSet.ReportingBeginDate));
            }

            if (!String.IsNullOrEmpty(_metadataSet.ReportingEndDate))
            {
                metadataSet.Add(new XAttribute("reportingEndDate", _metadataSet.ReportingEndDate));
            }

            if (!String.IsNullOrEmpty(_metadataSet.ValidFromDate))
            {
                metadataSet.Add(new XAttribute("validFromDate", _metadataSet.ValidFromDate));
            }

            if (!String.IsNullOrEmpty(_metadataSet.ValidToDate))
            {
                metadataSet.Add(new XAttribute("validToDate", _metadataSet.ValidToDate));
            }

            if (!String.IsNullOrEmpty(_metadataSet.PublicationYear))
            {
                metadataSet.Add(new XAttribute("publicationYear", _metadataSet.PublicationYear));
            }

            if (!String.IsNullOrEmpty(_metadataSet.PublicationPeriod))
            {
                metadataSet.Add(new XAttribute("publicationPeriod", _metadataSet.PublicationPeriod));
            }

            //Elements
            foreach (SDMX_Common.TextType name in _metadataSet.Name)
            {
                metadataSet.Add(ElementBuilder.GetTextType(name, "Name", _nsGenericMetadata));
            }

            if (_metadataSet.MetadataStructureRef != null)
            {
                if(_metadataSet.MetadataStructureRef.Value != null)
                {
                    metadataSet.Add(new XElement(_nsGenericMetadata + "MetadataStructureRef", _metadataSet.MetadataStructureRef.Value));
                }
            }

            if (_metadataSet.MetadataStructureAgencyRef != null)
            {
                if (_metadataSet.MetadataStructureAgencyRef.Value != null)
                {
                    metadataSet.Add(new XElement(_nsGenericMetadata + "MetadataStructureAgencyRef", _metadataSet.MetadataStructureAgencyRef.Value));
                }
            }

            if (_metadataSet.ReportRef != null)
            {
                if (_metadataSet.ReportRef.Value != null)
                {
                    metadataSet.Add(new XElement(_nsGenericMetadata + "ReportRef", _metadataSet.ReportRef.Value));
                }
            }

            if (_metadataSet.AttributeValueSet != null)
            {
                if (_metadataSet.AttributeValueSet.Count > 0)
                {
                    foreach (SDMX_Metadata.AttributesValueSetType attribute in _metadataSet.AttributeValueSet)
                    {
                        metadataSet.Add(new XElement(SetAttributeValueSet(attribute)));
                    }
                }
            }

            if (_metadataSet.Annotations != null)
            {
                metadataSet.Add(ElementBuilder.GetAnnotations(_metadataSet.Annotations, _nsGenericMetadata));
            }

            return metadataSet;
        }

        private XElement SetAttributeValueSet(SDMX_Metadata.AttributesValueSetType attributeValueSetType)
        {
            XElement attributeValueSet = new XElement(_nsGenericMetadata + "AttributeValueSet");

            if (attributeValueSetType.TargetRef != null)
            {
                if (attributeValueSetType.TargetRef.Value != null)
                {
                    attributeValueSet.Add(new XElement(_nsGenericMetadata + "TargetRef", attributeValueSetType.TargetRef.Value));
                }
            }

            if (attributeValueSetType.TargetValues != null)
            {
                attributeValueSet.Add(SetTargetValues(attributeValueSetType.TargetValues));
            }

            if (attributeValueSetType.ReportedAttribute != null)
            {
                if (attributeValueSetType.ReportedAttribute.Count > 0)
                {
                    foreach (SDMX_Metadata.ReportedAttributeType ra in attributeValueSetType.ReportedAttribute)
                    {
                        attributeValueSet.Add(SetReportedAttribute(ra));
                    }
                }
            }

            return attributeValueSet;
        }

        private XElement SetReportedAttribute(SDMX_Metadata.ReportedAttributeType ra)
        {
            XElement reportedAttribute = new XElement(_nsGenericMetadata + "ReportedAttribute");

           
                if (ra.ConceptID != null)
                {
                    if (ra.ConceptID.Value != null)
                    {
                        reportedAttribute.Add(new XAttribute("conceptID", ra.ConceptID.Value));
                    }
                }

                if (ra.Value != null)
                {
                    foreach (SDMX_Common.TextType value in ra.Value)
                    {
                        reportedAttribute.Add(ElementBuilder.GetTextType(value, "Value", _nsGenericMetadata));
                    }
                }

                if (!String.IsNullOrEmpty(ra.StartTime))
                {
                    reportedAttribute.Add(new XElement(_nsGenericMetadata + "StartTime", ra.StartTime));
                }

                if (ra.ReportedAttribute != null)
                {
                    if(ra.ReportedAttribute.Count > 0)
                    {
                        foreach (SDMX_Metadata.ReportedAttributeType at in ra.ReportedAttribute)
                        {
                            reportedAttribute.Add(SetReportedAttribute(at));
                        }
                    }
                }

                if (ra.Annotations != null)
                {
                    reportedAttribute.Add(ElementBuilder.GetAnnotations(ra.Annotations, _nsGenericMetadata));
                }
            

            return reportedAttribute;
        }

        private XElement SetTargetValues(SDMX_Metadata.TargetValuesType targetValuesType)
        {
            XElement targetValues = new XElement(_nsGenericMetadata + "TargetValues");

            foreach (SDMX_Metadata.ComponentValueType cv in targetValuesType.ComponentValue)
            {
                XElement compValue = new XElement(_nsGenericMetadata + "ComponentValue");

                if (cv.Component != null)
                {
                    if (cv.Component.Value != null)
                    {
                        compValue.Value = cv.Component.Value;
                    }
                }

                if (cv.Object != null)
                {
                    compValue.Add(new XAttribute("object", cv.Object.ToString()));
                }

                targetValues.Add(compValue);
            }


            return targetValues;
        }

        /// <summary>
        /// Writes the content to a xml file.
        /// </summary>
        /// <param name="file">Path and name of file.</param>
        /// <param name="content">Content of a SDMX_ML file.</param>
        public void Write(string file, string content)
        {
            try
            {
                using (TextWriter writer = new StreamWriter(file))
                {
                    try
                    {
                        writer.Write(content);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Unexpected error when wrting to file. " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Unexpected error when creating file. " + ex.Message);
            }
        }

        /// <summary>
        /// Load SDMX_ML Structure file into Structure object.
        /// </summary>
        /// <param name="file">Path and name of file.</param>
        /// <returns></returns>
        public static GenericMetadata Load(string file)
        {
            GenericMetadata structure = null;

            if (File.Exists(file))
            {
                using (TextReader reader = new StreamReader(file))
                {
                    string fileContent = reader.ReadToEnd();

                    try
                    {
                        structure = new GenericMetadata(fileContent);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Unexpected error when creating GenericMetadata object. " + ex.Message);
                    }
                }

                return structure;
            }
            else
            {
                throw new FileNotFoundException("File not found when trying to create GenericMetadata object.", file);
            }
        }
    }
}
